pub fn base_type_main() {
    //
    number_type();
}

fn number_type() {
    /*
    长度	    有符号类型	无符号类型
    8 位	    i8	        u8
    16 位	    i16	        u16
    32 位	    i32	        u32
    64 位	    i64	        u64
    128 位	    i128	    u128
    视架构而定	isize	    usize
    ---------------------------------
    类型定义的形式统一为：有无符号 + 类型大小(位数)；无符号数表示数字只能取正数和 0

    整形字面量可以用下表的形式书写：
    数字字面量	示例
    十进制	98_222
    十六进制	0xff
    八进制	0o77
    二进制	0b1111_0000
    字节 (仅限于 u8)	b'A'
    */
    /// | 类型 | 最大值（二进制） | 十进制值 | 计算逻辑                |
    /// |------|------------------|----------|-------------------------|
    /// | i8   | `01111111`       | 127      | 2^6 + 2^5 + ... + 2^0   |
    /// | u8   | `11111111`       | 255      | 2^7 + 2^6 + ... + 2^0   |
    assert_eq!(i8::MAX, 127);  // i8有符号，所有位表示数值，范围 -128~127。
    assert_eq!(u8::MAX, 255);  // u8无符号，所有位表示数值，范围 0~255。

    // Rust 默认使用的整型是 i32
    let x: i32 = 10;
    println!("x 的值是 {}", x);
    assert_eq!(100u8.saturating_add(1), 101);

    let mut y = 100u8;
    y += 1;
    assert_eq!(y, 101);

    // 会报错，因为浮点数精度问题，0.1 + 0.2 != 0.3
    // assert_eq!(0.1 + 0.2, 0.3);
    println!("0.1 + 0.2 的值是 {}", 0.1 + 0.2);


    // ----------------------------------------------
    /*
    to_bits() 是 Rust 中 f32 和 f64 类型的方法，用于将浮点数的 二进制位模式 转换为对应的整数类型：
        f32.to_bits() → 返回 u32（32位无符号整数）
        f64.to_bits() → 返回 u64（64位无符号整数）
    */
    let abc: (f32, f32, f32) = (0.1, 0.2, 0.3);
    let xyz: (f64, f64, f64) = (0.1, 0.2, 0.3);

    println!("abc (f32)");
    println!("   0.1 + 0.2: {:x}", (abc.0 + abc.1).to_bits());
    println!("         0.3: {:x}", (abc.2).to_bits());
    // 对 f32 类型做加法时，0.1 + 0.2 的结果是 3e99999a，0.3 也是 3e99999a，因此 f32 下的 0.1 + 0.2 == 0.3 通过测试
    println!();


    println!("xyz (f64)");
    println!("   0.1 + 0.2: {:x}", (xyz.0 + xyz.1).to_bits());
    println!("         0.3: {:x}", (xyz.2).to_bits());
    // 到了 f64 类型时，结果就不一样了，因为 f64 精度高很多，因此在小数点非常后面发生了一点微小的变化，0.1 + 0.2 以 4 结尾，但是 0.3 以3结尾
    println!();

    // assert!(abc.0 + abc.1 == abc.2);
    // assert!(xyz.0 + xyz.1 == xyz.2);

    // ----------------------------------------------
    // NaN：Not a Number，不是数字，在 Rust 中用 f32::NAN 和 f64::NAN 表示。例如对负数取平方根 -42.1.sqrt()
    // 所有跟 NaN 交互的操作，都会返回一个 NaN，而且 NaN 不能用来比较
    let x = (-42.0_f32).sqrt();
    println!("x 的值是 {}", x);  // x 的值是 NaN
    // assert_eq!(x, x);

    // 可以使用 is_nan() 等方法判断一个数值是否是 NaN
    if x.is_nan() {
        println!("未定义的数学行为");
    };

    // ----------------------------------------------
    // 综合示例
    // 编译器会进行自动推导，给予twenty i32的类型
    let twenty = 20;

    // 类型标注
    let twenty_one: i32 = 21;

    // 通过类型后缀的方式进行类型标注：22是i32类型
    let twenty_two = 22i32;

    // 只有同样类型，才能运算
    let addition = twenty + twenty_one + twenty_two;
    println!("{} + {} + {} = {}", twenty, twenty_one, twenty_two, addition);

    // 对于较长的数字，可以用_进行分割，提升可读性
    let one_million: i64 = 1_000_000;
    println!("{}", one_million.pow(2));

    // 定义一个f32数组，其中42.0会自动被推导为f32类型
    let forty_twos = [
        42.0,
        42f32,
        42.0_f32,
    ];

    // 打印数组中第一个值，并控制小数位为2位
    println!("{:.2}", forty_twos[0]);

    // ----------------------------------------------
    // 类型转换
    let x = 5;
    let y: f64 = x as f64;

    struct Person {
        name: String,
        age: i32,
    }
    let person = Person {
        name: "Alice".to_string(),
        age: 20,
    };
    print_type_of(&person);

    enum MixedType {
        Int(i32),
        Float(f64),
        Char(char),
        Bool(bool),
        String(String),
        Vec(Vec<i32>),
        Tuple(i32, i32, i32),
        Array([i32; 3]),
        Enum(Box<MixedType>),
    }
    let z = [
        MixedType::Char('1'),
        MixedType::Char('2'),
        MixedType::Char(' '),
        MixedType::Int(4),
        MixedType::Int(5),
        MixedType::Array([1, 2, 3])
    ];
    print_type_of(&z);

    println!("x: {} y: {}", x, y);
    assert_eq!(y, 5.0);

    let d = 1.0;
    print_type_of(&(d.to_string()));
    // ----------------------------------------------
    // 循环遍历
    // range_type();
}


fn range_type() {
    // ----------------------------------------------
    // 开区间  1 2 3 4
    for i in 1..5 {
        println!("{}", i);
    }

    // ----------------------------------------------
    // 闭区间  1 2 3 4 5
    for i in 1..=5 {
        println!("{}", i);
    }

    // ----------------------------------------------
    for i in 'a'..='z' {
        println!("{}",i);
    }
}


fn print_type_of<T>(_: &T) {
    println!("Type: {}", std::any::type_name::<T>());
}